﻿using RAP.Framework.Libary.Configuration;
using RAP.Framework.Libary.DataSource;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using RAP.Framework.Libary.Utils;
using RAP.Web.Libary.Service.Session;
using RAP.Web.Libary.Service.Attributes;
using RAP.Web.Libary.Service;
using RAP.Web.Libary.Common.Model;
using RAP.Framework.Libary.SqlDataService.Service;
using RAP.Web.Libary.Common;
using RAP.Web.Libary.Common.Model.Session;
using RAP.Web.Core.Server.Common.Model;
using Microsoft.Extensions.DependencyInjection;
using RAP.Framework.Libary.DataSource.Model;
using RAP.Framework.Libary.DataSource.Context;

namespace RAP.Web.Core.Server.Service
{
  /// <summary>
  /// 用户信息服务对象
  /// </summary>
  [ServiceScope( ScopeType = ServiceScopeTypes.Singleton, ServiceType = typeof( IUserInfoService ) )]
  public class UserInfoService : APIServiceBase, IUserInfoService
  {
    /// <summary>
    /// 用户回话缓存
    /// </summary>
    public static IDictionary<string, IWebUserSession> UserSessions { get; } = new Dictionary<string, IWebUserSession>();

    /// <summary>
    /// 
    /// </summary>
    private IDictionary WXConfig { get; set; }

    public UserInfoService(
        IServiceProvider serviceProvider,
        IConfigurationManager configuration ) : base( serviceProvider )
    {
      this.WXConfig = configuration.ToDictionary( "WeiXin" );
    }

    /// <summary>
    /// 用户登出
    /// </summary>
    /// <param name="param"></param>
    /// <returns></returns>
    public async Task<object> Logout( IQueryParams param )
    {
      var queryParams = param as IAPIQueryParams;
      var token = queryParams.Token;
      if ( token.IsNullOrEmpty() )
      {
        return ServiceUtils.CreateErrorResult( "会话无效！" );
      }
      await this.SqlDataService.ExecuteNonQuery( queryParams );
      UserSessions.Remove( token );
      return true;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="param"></param>
    /// <returns></returns>
    public async Task<object> Login( IQueryParams param )
    {
      return await WXLogin( param );
    }

    /// <summary>
    /// 微信登录
    /// </summary>
    /// <param name="param"></param>
    /// <returns></returns>
    public async Task<object> WXLogin( IQueryParams param )
    {
      var queryParams = param as IAPIQueryParams;
      var openid = queryParams.ToString( FieldConsts.OpenIdField );
      var code = queryParams.ToString( FieldConsts.CodeField );
      var token = $"{FieldConsts.TokenField}_{code}_{DateTime.Now.Ticks}".MD5Encrypt();

      var res = await this.GetWXUserInfo( queryParams );
      if ( res.HasError() )
      {
        return this.ErrorContent( "获取微信用户信息失败！" );
      }
        ( res as IDictionary ).CopyTo( queryParams );
      queryParams.Token = token;

      res = await this.SqlDataService.ExecuteNoCache( queryParams );
      if ( res.HasError() )
      {
        return res;
      }
      if ( res.GetFirstResultId() == 0 )
      {
        return this.ErrorContent( "登录失败！可能是由于用户或设备已被禁用（过期）等原因造成。" );
      }
      var session = await this.GetUserSession( queryParams );
      return new
      {
        userInfo = session.UserInfo,
        token
      };
    }

    /// <summary>
    /// 获取微信的Token等信息
    /// </summary>
    /// <returns></returns>
    private async Task<object> GetWXAccessToken( IDictionary param )
    {
      this.WXConfig.CopyTo( param, "AppID", "AppSecret" );
      var getAccessTokenUrl = this.WXConfig.ToString( "GetAccessTokenUrl" ).Translator( param );
      return await getAccessTokenUrl.HttpGet();
    }

    /// <summary>
    /// 获取微信用户信息
    /// </summary>
    /// <param name="param"></param>
    /// <returns></returns>
    public async Task<object> GetWXUserInfo( IAPIQueryParams param )
    {
      var res = await this.GetWXAccessToken( param );
      if ( res.HasError() )
      {
        return res;
      }
      var tokenRes = res.ToDictionary();
      tokenRes.CopyTo( param, "access_token", "refresh_token", "openid" );
      var getUserInfoUrl = this.WXConfig.ToString( "GetUserInfoUrl" ).Translator( param );
      res = await getUserInfoUrl.HttpGet();
      if ( res.HasError() )
      {
        return res;
      }
      var userInfoRes = res.ToDictionary();
      userInfoRes.CopyTo( param, "nickname", "sex", "province", "city", "country", "headimgurl", "privilege" );
      //return await this.SqlDataService.ExecuteNoCache( param );
      return userInfoRes;
    }

    /// <summary>
    /// 查询用户的数据权限
    /// </summary>
    /// <param name="param"></param>
    /// <returns></returns>
    public async Task<object> HasDataPower( IAPIQueryParams param )
    {
      var res = await this.SqlDataService.ExecuteNoCache( param );
      if ( res.HasError() )
      {
        return res;
      }
      return res.GetFirstResultValue( FieldConsts.ValueField );
    }

    /// <summary>
    /// 根据Token获取用户的会话信息
    /// </summary>
    /// <param name="param"></param>
    /// <returns></returns>
    public async Task<IUserSession> GetUserSession( IAPIQueryParams queryParams )
    {
      var token = queryParams.Token;
      if ( !UserSessions.TryGetValue( token, out IWebUserSession session ) )
      {
        var res = await this.SqlDataService.ExecuteNoCache( queryParams );
        if ( res.HasError )
        {
          return null;
        }
        var dataPowers = res.Data.GetRecordset<IList>( FieldConsts.UserDataPowersField );
        var dataPowerObjs = new Hashtable();
        if ( dataPowers.IsNotNullOrEmpty() )
        {
          foreach ( IDictionary power in dataPowers )
          {
            var code = power.ToString( FieldConsts.CodeField );
            var list = dataPowerObjs.ToList( code );
            if ( list == null )
            {
              dataPowerObjs[ code ] = list = new ArrayList();
            }
            list.Add( power[ FieldConsts.CityCodeField ] );
          }
        }
        var data = res.Data as IDictionary;
        session = ServiceProvider.GetService<IUserSession>() as IWebUserSession;
        session.UserInfo = data.GetValue<IUserInfo>( "userInfo" );
        session.Menus = data.GetRecordset<IList>( FieldConsts.UserMenusField ).ToDictionaryObject<IDictionary, string>( item => item.ToString( FieldConsts.CodeField ) );
        session.DataPowers = dataPowerObjs;
        session.Token = token;
      }
      UserSessions[ token ] = session;
      return session;
    }

    /// <summary>
    /// 保存用户信息
    /// </summary>
    /// <param name="param"></param>
    /// <returns></returns>
    public async Task<object> SaveUserInfo( IQueryParams param )
    {
      return await this.SqlDataService.ExecuteNonQuery( param );
    }
  }
}
